package Model;

import java.util.ArrayList;

/**
 * this is the class used to represent an animal
 */
public class Animal extends Being {
    // ATTRIBUTE

    private AnimalType type;

    // CONSTRUCTOR
    public Animal(int id, int speed, Location location, int visionRadius, AnimalType type) {
        super(id, speed, location, visionRadius, true);
        this.setResourceBrought(new Resource(ResourceType.Food, 50));
        this.type = type;
        this.activity = Activity.None;
    }

    // OWN FUNCTIONS
    //TO DO
    public ArrayList<DirectionWeighted> humansAround(ArrayList<Square> environmentInRadius) {
        // declaration
        // res - final res to return.
        ArrayList<DirectionWeighted> res = new ArrayList<DirectionWeighted>();
        // resAux : contains all the Direction (possible doublon) with weight.
        ArrayList<DirectionWeighted> resAux = new ArrayList<DirectionWeighted>();
        // the beings in the environment.
        ArrayList<Being> beingsInEnv = getBeingsInEnvironment(environmentInRadius);
        // the DirecionWeighted to be added to the final result
        DirectionWeighted WestWeight = new DirectionWeighted(Direction.West, 0);
        DirectionWeighted NorthWeight = new DirectionWeighted(Direction.North, 0);
        DirectionWeighted EastWeight = new DirectionWeighted(Direction.East, 0);
        DirectionWeighted SouthWeight = new DirectionWeighted(Direction.South, 0);

        // code
        for (int i = 0; i < beingsInEnv.size(); i++) {
            if (!beingsInEnv.get(i).isAnimal()) {
                // get the directions in which the danger is
                ArrayList<Direction> directionList = this.getLocation().getRelativeDirection(beingsInEnv.get(i).getLocation());

                // get the distance between this & the danger
                int weight = Parameter.getMaxFearDistance() - this.getLocation().getRelativeDistance(beingsInEnv.get(i).getLocation());

                for (int j = 0; j < directionList.size(); j++) // add danger with weight to resAux
                {
                    DirectionWeighted directionWeighted = new DirectionWeighted(directionList.get(j), weight);
                    resAux.add(directionWeighted);
                }
            }
        }

        // transfer resAux to res with appropriate weights
        for (int i = 0; i < resAux.size(); i++) {
            switch (resAux.get(i).getDirection()) {
                case West:
                    WestWeight.setWeight(WestWeight.getWeight() + resAux.get(i).getWeight());
                    break;
                case North:
                    NorthWeight.setWeight(NorthWeight.getWeight() + resAux.get(i).getWeight());
                    break;
                case East:
                    EastWeight.setWeight(EastWeight.getWeight() + resAux.get(i).getWeight());
                    break;
                case South:
                    SouthWeight.setWeight(SouthWeight.getWeight() + resAux.get(i).getWeight());
                    break;
                default:
                    break;
            }
        }
        res.add(WestWeight);
        res.add(NorthWeight);
        res.add(EastWeight);
        res.add(SouthWeight);
        return res;
    }

    //TO DO
    @Override
    public void doSpecificAction(Action action, Square actionSquare) {
        // TODO Auto-generated method stub
    }

    //TO DO
    public Action decideAction(ArrayList<Square> environmentInRadius, ArrayList<Square> directEnvironement) {
        DecisionMatrix decisionMatrix = new DecisionMatrix();

        ArrayList<DirectionWeighted> dangerDirection = humansAround(environmentInRadius);
        ArrayList<DirectDirection> POIHandToHand = poiInHtH(directEnvironement);

        // CONSTRUCTION OF DECISION MATRIX
        // TREATMENT DANGER
        int rowToModify = 0;

        if (this.type != AnimalType.Lion) {
            //For lions, humans are POI => MovePoi
            rowToModify = 1;
        } else {
            //For cows and does, humans are danger => Escape
            rowToModify = 0;
        }

        for (DirectionWeighted dw : dangerDirection) {
            int weight = dw.getWeight();

            switch (dw.getDirection()) {
                case North:
                    decisionMatrix.addVectorToRow(rowToModify, (new int[]{weight, weight, weight, 0, 0, 0, 0, 0}));
                    break;
                case South:
                    decisionMatrix.addVectorToRow(rowToModify, (new int[]{0, 0, 0, 0, 0, weight, weight, weight}));
                    break;
                case West:
                    decisionMatrix.addVectorToRow(rowToModify, (new int[]{weight, 0, 0, weight, 0, weight, 0, 0}));
                    break;
                case East:
                    decisionMatrix.addVectorToRow(rowToModify, (new int[]{0, 0, weight, 0, weight, 0, 0, weight}));
                    break;
                default:
                    break;
            }
        }


        for (int i = 0; i < POIHandToHand.size(); i++) {
            if (!POIHandToHand.isEmpty()) // secure test
            {
                switch (POIHandToHand.get(i)) {
                    case NorthWest:
                        decisionMatrix.setDecisionNO(2, Parameter.getActionWeight());
                        break;
                    case North:
                        decisionMatrix.setDecisionN(2, Parameter.getActionWeight());
                        break;
                    case NorthEast:
                        decisionMatrix.setDecisionNE(2, Parameter.getActionWeight());
                        break;
                    case West:
                        decisionMatrix.setDecisionO(2, Parameter.getActionWeight());
                        break;
                    case East:
                        decisionMatrix.setDecisionE(2, Parameter.getActionWeight());
                        break;
                    case SouthWest:
                        decisionMatrix.setDecisionSO(2, Parameter.getActionWeight());
                        break;
                    case South:
                        decisionMatrix.setDecisionS(2, Parameter.getActionWeight());
                        break;
                    case SouthEast:
                        decisionMatrix.setDecisionSE(2, Parameter.getActionWeight());
                        break;
                }
            }
        }


        // POST TREATMENT -- No Collision, No Moving into Obstacle
        // NULLIFY WEIGHT OF OBSTACLE SQUARES
        if (decisionMatrix.isZeroExceptRowGoTarget()) {
            int[] randomMove = {1, 1, 1, 1, 1, 1, 1, 1};
            decisionMatrix.addVectorToRow(1, randomMove);
        }
        DirectDirection direction;
        int[] isSquareOk = {0, 0, 0, 0, 0, 0, 0, 0};
        int[] isEscapeOk = {0, 0, 0, 0, 0, 0, 0, 0};
        for (Square square : directEnvironement) {
            direction = this.getLocation().whatDirectDirectionWith(square.getLocation());

            switch (direction) {
                case NorthWest:
                    isSquareOk[0] = (square.isObstacle()) ? 0 : 1;
                    break;
                case North:
                    isSquareOk[1] = (square.isObstacle()) ? 0 : 1;
                    break;
                case NorthEast:
                    isSquareOk[2] = (square.isObstacle()) ? 0 : 1;
                    break;
                case West:
                    isSquareOk[3] = (square.isObstacle()) ? 0 : 1;
                    break;
                case East:
                    isSquareOk[4] = (square.isObstacle()) ? 0 : 1;
                    break;
                case SouthWest:
                    isSquareOk[5] = (square.isObstacle()) ? 0 : 1;
                    break;
                case South:
                    isSquareOk[6] = (square.isObstacle()) ? 0 : 1;
                    break;
                case SouthEast:
                    isSquareOk[7] = (square.isObstacle()) ? 0 : 1;
                    break;
                default:
                    break;
            }
        }
        
        isEscapeOk[0] = isSquareOk[7];//
        isEscapeOk[1] = isSquareOk[6];//
        isEscapeOk[2] = isSquareOk[5];//
        isEscapeOk[3] = isSquareOk[4];//
        isEscapeOk[4] = isSquareOk[3];//
        isEscapeOk[5] = isSquareOk[2];//
        isEscapeOk[6] = isSquareOk[1];//
        isEscapeOk[7] = isSquareOk[0];//

        decisionMatrix.multiplyVectorToRow(3, isSquareOk);
        decisionMatrix.multiplyVectorToRow(1, isSquareOk);
        decisionMatrix.multiplyVectorToRow(0, isEscapeOk);


        Action action = null;

        if (!decisionMatrix.isZero()) {
            decisionMatrix.sumInStats();
            action = decisionMatrix.chooseAction();
            if(action.getDecision() == 2) {
                System.out.println("Lion attack !!");
            }
        }
        return action;
    }
// GETTER - SETTER

    public AnimalType getType() {
        return this.type;
    }

    public void setType(AnimalType newAnimalType) {
        this.type = newAnimalType;
    }
    //For lions : poi = humans + does + cows

    public ArrayList<DirectDirection> poiInHtH(ArrayList<Square> directNeighbours) {
        ArrayList<DirectDirection> res = new ArrayList<DirectDirection>();
        
        //Does and cows don't have poi atm
        if(!this.type.equals(AnimalType.Lion)) {
            return res;
        }
        
        for (int i = 0; i < directNeighbours.size(); i++) {
            if (directNeighbours.get(i).getBeingReference() != null) {
                if (!directNeighbours.get(i).getBeingReference().isAnimal() || ((Animal) directNeighbours.get(i).getBeingReference()).getType() != AnimalType.Lion) {
                    DirectDirection dd = this.getLocation().whatDirectDirectionWith(directNeighbours.get(i).getLocation());
                    res.add(dd);
                }
            }
        }


        return res;
    }
}
